/*	This file is part of LSAC.

	LSAC is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	LSAC is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with LSAC.  If not, see <http://www.gnu.org/licenses/>.

	Copyright (c) 2010 LEPESME "Jiboo" Jean-Baptiste
*/

#include <cassert>
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <cxxabi.h>
#include <typeinfo>
using namespace std;

#include "cLexer.h"
#include "lsac.h"

cLexer::cLexer(string pFilename)
{
	ifstream lStream;
	unsigned int lCurLine = 1, lCurColumn = 1;
	char lChar;
	cToken *lToken = NULL;

	lStream.open(pFilename.c_str(), ios::binary);
	if(!lStream)
	{
		ERROR("impossible d' ouvrir le fichier " << pFilename);
		abort();
	}

	while(!lStream.eof())
	{
		lStream.get(lChar);

		if(!lStream.eof())
		{
			switch(lChar)
			{
			case '=' :
				if(lToken == NULL && (this->dTokens.back()->dValue == "<" || this->dTokens.back()->dValue == ">")) // On suppose l' operateur <= ou >=
				{
					this->dTokens.back()->addChar('=');
					break;
				}
			case '-' :
				if(lToken == NULL && (this->dTokens.back()->dValue == "<")) // On suppose l' operateur <-
				{
					this->dTokens.back()->addChar('-');
					break;
				}
			case '<' :
			case '*' :
			case '/' :
			case '(' :
			case ')' :
			case ',' :
			case ';' :
			case '+' :
				if(lToken != NULL)
				{
					this->dTokens.push_back(lToken);
				}
				lToken = new cToken(lCurLine, lCurColumn, lChar);
				this->dTokens.push_back(lToken);
				lToken = NULL;
				break;
			case ' ':
			case '\t':
			case '\n':
				if(lToken != NULL)
				{
					this->dTokens.push_back(lToken);
					lToken = NULL;
				}
				if(lChar=='\n')
				{
					lCurLine++;
					lCurColumn = 0; // = 1 Car on a un lCurColumn++ plus loin
				}
				break;
			case '\r':
				break;
			default:
				if(lToken == NULL)
				{
					lToken = new cToken(lCurLine, lCurColumn, lChar);
				}
				else
				{
					lToken->addChar(lChar);
				}
			}
			lCurColumn++;
		}
	}
	if(lToken != NULL)
	{
		this->dTokens.push_back(lToken);
	}
}

cLexer::~cLexer()
{
	list<cToken*>::iterator lIterator = this->dTokens.begin();
	for(; lIterator != this->dTokens.end(); lIterator++)
	{
		//delete (*lIterator);
	}
}

cToken *cLexer::pop()
{
	if(this->dTokens.size() == 0) return NULL;
	cToken *lToken = this->dTokens.front();
	this->dTokens.pop_front();
	return lToken;
}

cToken *cLexer::next(int pIndex)
{
	if(this->dTokens.size() == 0) return NULL;
	list<cToken*>::iterator lIterator = this->dTokens.begin();
	for(int lIndex = 0; lIndex < pIndex; lIndex++)
	{
		lIterator++;
	}
	return (*lIterator);
}

void cLexer::print()
{
	list<cToken*>::iterator lIterator = this->dTokens.begin();
	for(; lIterator != this->dTokens.end(); lIterator++)
	{
		LOG(*lIterator);
	}
}

unsigned int cLexer::size()
{
	return this->dTokens.size();
}

ostream& operator<<(ostream& o, const cLexer& pToken)
{
	list<cToken*>::const_iterator lIterator = pToken.dTokens.begin();
	for(; lIterator != pToken.dTokens.end(); lIterator++)
	{
		o << *(*lIterator) << endl;
	}
	return o;
}
